#ifndef     __DMA_H
#define     __DMA_H

#include "./compat.h"

namespace device {

template <uint32_t Id, uint32_t StreamId>
struct Dma {

    static constexpr uint32_t Flags = 0x3D;

    static inline void ClrFlag() {
        assert();
        constexpr uint32_t Mask = Flags << getFlagOffset();
        if constexpr (Id == 1) {
            if constexpr (StreamId <= 3) {
                DMA1->LIFCR = Mask;
            } else {
                DMA1->HIFCR = Mask;
            }
        } else {
            if constexpr (StreamId <= 3) {
                DMA2->LIFCR = Mask;
            } else {
                DMA2->HIFCR = Mask;
            }
        }
    }

    // 传输完成
    static inline bool IsTC() {
        constexpr uint32_t Mask = 0x20 << getFlagOffset();
        return IsFlag(Mask);
    }

    static inline bool IsFlag(uint32_t flag) {
        assert();
        if constexpr (Id == 1) {
            if constexpr (StreamId <= 3) {
                return (DMA1->LISR & flag) != 0;
            } else {
                return (DMA1->HISR & flag) != 0;
            }
        } else {
            if constexpr (StreamId <= 3) {
                return (DMA2->LISR & flag) != 0;
            } else {
                return (DMA2->HISR & flag) != 0;
            }
        }
    }

private:
    static constexpr uint32_t getFlagOffset() {
        if constexpr ((StreamId == 0) || (StreamId == 4)) {
            return 0;
        } else if constexpr ((StreamId == 1) || (StreamId == 5)) {
            return 6;
        } else if constexpr ((StreamId == 2) || (StreamId == 6)) {
            return 16;
        } else { // 3 or 7
            return 22;
        }
    }

    static inline void assert() {
        static_assert((Id == 1) || (Id == 2), "dma id fail");
        static_assert(StreamId <= 7, "dam stream id fail");
    }
};

}



#endif
